﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace com.ReinforceLab.AudioModem.FSK
{
    /// <summary>
    /// FSK バイトデータ伝送
    ///   ボーレート: 2400， 4800， 9600 のいずれか
    ///   変調方式: FPSK    
    ///   ビットオーダー: LSb-first (先頭は最下位ビット) 
    ///   同期方式: キャラクタ同期(0x7e)， エスケープキャラクタは(0x7d)
    ///   
    /// キャリア検出: Carrier未検出条件は、10秒以上の通信がないこと。
    /// レイテンシ: 規定せず。(タイマ割り込み周期は100msecをデフォルト値に。レイテンシ=送信データ時間 (16バイトで14msec@9600bps)+ (送受信遅れ(OpenAL)+タイマー(100msec) ~ 200msec程度)
    /// </summary>
    public class FSKModem : IModem, IAudioSource
    {
        #region Variables
        const int _mark1SamplesPerCycle = 8;
        const int _maxSamplingRate = 44100;

        readonly BaudRate  _baudRate;
        readonly int       _samplingRate;
        readonly IPacketSource _packetSource;        

        FSKModulator   _modulator; 
        IAudioPHY _phy;        
        #endregion

        #region Constructor
        public FSKModem(BaudRate baudRate, IPacketSource packetSource)
        {
            _baudRate = baudRate;
            _packetSource = packetSource;

            _samplingRate = (int)_baudRate * _mark1SamplesPerCycle;
            if(_samplingRate > _maxSamplingRate)
                throw new ArgumentOutOfRangeException("baudRate","Baud rage is out of range. It should be less than " + (_maxSamplingRate / _mark1SamplesPerCycle).ToString() +".");
        }
        #endregion

        #region IAudio Source            
        public void InSignal(short[] waveform, int validLength)            
        {
                // TODO                        
        }
        public short[] OutSignal(out int validLength)
        {

            return _modulator.Send(out validLength);
        }            
        #endregion
            
        #region IModem メンバ        
        public int SamplingRate  { get{return _samplingRate;}}
        public BaudRate BaudRate { get{return _baudRate;}}
        public bool IsRunning
        {
            get
            {
                if (_phy == null)
                    return false;
                else
                    return _phy.IsRunning;
            }
        }  
        public void Start(IAudioPHY phy)
        {
            if (IsRunning)
                return;
            
            // parameter check
            if (null == phy)
                throw new ArgumentNullException();
            if (phy.SamplingRate != _samplingRate)
                throw new ArgumentOutOfRangeException("phy", 
                    String.Format("Sampling rate of the audio physical interface {0} is not the same to that of this modem {1}.", phy.SamplingRate, _samplingRate));

            _phy = phy;
            _modulator = new FSKModulator(_phy, _packetSource, _mark1SamplesPerCycle);
            _phy.Start(this);
        }
        public void Stop()
        {
            if (!IsRunning)
                return;

            if (_phy == null)
                return;
            
            _phy.Stop(true);
            _phy = null;
            _modulator = null;            
        }
      
        #endregion

        #region IDisposable メンバ
        public void Dispose()
        {
            if (null != _phy)
            {
                Stop();
                
                _phy.Dispose();
                _phy = null;

                _modulator = null;                
            } 
        }
        #endregion


    }
}
